﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using C4F.DevKit.Calendar.Parser;

namespace C4F.DevKit.Calendar.Components
{
    /// <summary>
    /// This component provides access to much of the calendaring functionality in a single component.
    /// </summary>
    [ToolboxItem(true),System.Drawing.ToolboxBitmap(typeof(CalendarService))]
    public partial class CalendarService : Component
    {
        #region Private Data

        private CalendarManager _calendarManager = new CalendarManager();

        private string _calendarFilePath;

        #endregion Private Data

        #region Private Properties

        [Browsable(false)]
        private CalendarManager CalendarManager
        {
            get
            {
                return _calendarManager;
            }
        }

        #endregion

        #region Constants

        private const string CALENDAR_FILE_EXTENSION = "ics";

        #endregion Constants

        #region Public Properties
        
        /// <summary>
        /// The path to the file in which the current calendar is stored.
        /// </summary>
        public string CalendarFilePath
        {
            get
            {
                return _calendarFilePath;
            }
            set
            {
                _calendarFilePath = value;
            }
        }

        /// <summary>
        /// The path to the folder where Windows stores calendar files by default.
        /// </summary>
        public string WindowsCalendarFolderPath
        {
            get
            {
                if (CalendarManager != null)
                    return CalendarManager.WindowCalendarFolderPath;
                else
                    return string.Empty;
            }
        }

        #endregion Public Properties

        #region Constructor

        /// <summary>
        /// Creates a new Calendar Service component.
        /// </summary>
        public CalendarService()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Creates a new Calendar Service component.
        /// </summary>
        /// <param name="container">The container to which to add this component.</param>
        public CalendarService(IContainer container)
        {
            container.Add(this);
            InitializeComponent();
        }

        #endregion Constructor

        #region Private Methods

        private string GetSaveFilePath(string pathToTry)
        {
            string filePath = pathToTry;

            if(string.IsNullOrEmpty(filePath))
                filePath = CalendarFilePath;
            
            if (string.IsNullOrEmpty(filePath))            
                filePath = PromptForSaveLocation();

            return filePath;
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Displays a file dialog and prompts the user to enter a location to save
        /// a calendar file.
        /// </summary>
        /// <returns>The path file path selected by the user, or the empty string if they cancelled
        /// the dialog.</returns>
        public string PromptForSaveLocation()
        {
            string filePath = string.Empty;

            using (SaveFileDialog dlg = new SaveFileDialog())
            {
                dlg.AddExtension = true;
                dlg.CheckPathExists = true;
                dlg.Filter = string.Format("Calendar Files (*.{0})|*.{0}|All files (*.*)|*.*", CALENDAR_FILE_EXTENSION);

                if (string.IsNullOrEmpty(this.CalendarFilePath) && Directory.Exists(WindowsCalendarFolderPath))
                    dlg.InitialDirectory = WindowsCalendarFolderPath;

                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    filePath = dlg.FileName;
                }
                else
                {
                    filePath = string.Empty;
                }
            }

            return filePath;
        }

        /// <summary>
        /// Displays an open file dialog and prompts the user to select a
        /// calendar file to open.
        /// </summary>
        /// <returns>The path of the file to open, or the empty string if the
        /// user cancelled the dialog.</returns>
        public string PromptForOpenLocation()
        {
            string filePath = string.Empty;

            using (OpenFileDialog dlg = new OpenFileDialog())
            {
                dlg.AddExtension = true;
                dlg.CheckPathExists = true;
                dlg.Filter = string.Format("Calendar Files (*.{0})|*.{0}|All files (*.*)|*.*", CALENDAR_FILE_EXTENSION);
                dlg.Multiselect = false;

                if (string.IsNullOrEmpty(this.CalendarFilePath) && Directory.Exists(WindowsCalendarFolderPath ))
                    dlg.InitialDirectory = WindowsCalendarFolderPath;

                if (dlg.ShowDialog() == DialogResult.OK)
                    filePath = dlg.FileName;
                else
                    filePath = string.Empty;
            }

            return filePath;
        }

        /// <summary>
        /// Retrieves all appointments from the current calendar (specified by
        /// CalendarFilePath), or a user-selected calendar if there is no
        /// current calendar.
        /// </summary>
        /// <returns>A collection of all the appointments from the calendar.</returns>
        public IEnumerable<Appointment> GetAllAppointments()
        {
            if (string.IsNullOrEmpty(CalendarFilePath))
                return this.GetAllAppointments(null);
            else
                return this.GetAllAppointments(CalendarFilePath);
        }
      
        /// <summary>
        /// Retrieves all appointments from the calendar specified.
        /// </summary>
        /// <param name="filePath">The path of the calendar file to get appointments from.
        /// If this is null, CalendarService will use CalendarFilePath, or prompt the user
        /// for a file if CalendarFilePath is null.</param>
        /// <returns>A collection of all the appointments from the calendar.</returns>
        public IEnumerable<Appointment> GetAllAppointments(string filePath)
        {
            if (CalendarManager == null)
                throw new CalendarManagerIsNullException("CalendarManager property has not been set.");

            if (string.IsNullOrEmpty(filePath))
                filePath = CalendarFilePath;

            if (string.IsNullOrEmpty(filePath))
                filePath = PromptForOpenLocation();

            return CalendarManager.GetAllAppointments(filePath);
        }

        /// <summary>
        /// Creates a new calendar, prompting the user to select a place to save
        /// the file.
        /// </summary>
        public void CreateCalendar()
        {
            string calendarPath = PromptForSaveLocation();

            if (string.IsNullOrEmpty(calendarPath))
            {
                return;
            }

            CalendarManager.CreateCalendar(calendarPath);
            CalendarFilePath = calendarPath;
        }

        /// <summary>
        /// Adds the specified appointments to the specified calendar file.
        /// </summary>
        /// <param name="filePath">The file of the calendar to save the appointments to.
        /// If this is null, CalendarService will use CalendarFilePath, or failing that, will
        /// prompt the user for a location.</param>
        /// <param name="appts">The appointments to add.</param>
        public void AddAppointments(string filePath, IEnumerable<Appointment> appts)
        {
            if (CalendarManager == null)
                throw new CalendarManagerIsNullException("CalendarManager property has not been set.");

            filePath = GetSaveFilePath(filePath);

            if (string.IsNullOrEmpty(filePath))
                return;

            CalendarManager.AddAppointments(filePath, appts);
        }

        /// <summary>
        /// Adds the specified appointments to the current calendar, or if there is
        /// none, to the calendar specified by the user when they are prompted.
        /// </summary>
        /// <param name="appts">The appointments to add.</param>
        public void AddAppointments(IEnumerable<Appointment> appts)
        {
            AddAppointments(string.Empty, appts);
        }

        /// <summary>
        /// Adds the specified appointments to the current calendar, or if there is
        /// none, to the calendar specified by the user when they are prompted.
        /// </summary>
        /// <param name="appt">The appointments to add.</param>
        public void AddAppointment(Appointment appt)
        {
            if (string.IsNullOrEmpty(CalendarFilePath))
            {
                AddAppointment(null, appt);
            }
            else
            {
                AddAppointment(CalendarFilePath, appt);
            }
        }

        /// <summary>
        /// Adds the specified appointment to the specified calendar file.
        /// </summary>
        /// <param name="filePath">The file of the calendar to add the appointment to.
        /// If this is null, CalendarService will use CalendarFilePath, or failing that, will
        /// prompt the user for a location.</param>
        /// <param name="appt">The appointment to add.</param>
        public void AddAppointment(string filePath, Appointment appt)
        {
            if (CalendarManager == null)
                throw new CalendarManagerIsNullException("CalendarManager property has not been set.");

            if (string.IsNullOrEmpty(filePath))
                filePath = CalendarFilePath;

            if (string.IsNullOrEmpty(filePath))
                filePath = PromptForOpenLocation();

            if (string.IsNullOrEmpty(filePath))
                return;

            CalendarManager.AddAppointment(filePath, appt);
        }

        /// <summary>
        /// Updates the information in an existing appointment.
        /// </summary>
        /// <param name="appt">The new version of the appointment to put in the calendar. This appointment
        /// will replace the appointment in the Calendar with the same UID.</param>
        public void EditAppointment(Appointment appt)
        {
            EditAppointment(CalendarFilePath, appt);
        }

        /// <summary>
        /// Updates the information in an existing appointment.
        /// </summary>
        /// <param name="appt">The new version of the appointment to put in the calendar. This appointment
        /// will replace the appointment in the Calendar with the same UID.</param>
        /// <param name="filePath">The calendar file to be edited.</param>
        public void EditAppointment(string filePath, Appointment appt)
        {
            if (CalendarManager == null)
                throw new CalendarManagerIsNullException("CalendarManager property has not been set.");

            filePath = GetSaveFilePath(filePath);

            if (string.IsNullOrEmpty(filePath))
                return;

            CalendarManager.EditAppointment(filePath, appt);
        }

        /// <summary>
        /// Prompts the user for a calendar file and imports the events from
        /// that calendar into the current calendar.
        /// </summary>
        public void ImportCalendar()
        {
            string calendarToImport = PromptForOpenLocation();

            if (string.IsNullOrEmpty(calendarToImport))
            {
                return;
            }

            ImportCalendar(calendarToImport);
        }

        /// <summary>
        /// Prompts the user for a location to which to save the current calendar,
        /// and exports the current calendar to a file in that location.
        /// </summary>
        public void ExportCalendar()
        {
            string exportTarget = PromptForSaveLocation();

            if (string.IsNullOrEmpty(exportTarget))
            {
                return;
            }

            ExportCalendar(exportTarget);
        }

        /// <summary>
        /// Imports appointments from a calendar into the current calendar.
        /// </summary>
        /// <param name="filePath">The path of the calendar file to import.</param>
        public void ImportCalendar(string filePath)
        {
            CalendarManager.ImportCalendar(filePath, CalendarFilePath);
        }

        /// <summary>
        /// Exports appointments from the current calendar to a file.
        /// </summary>
        /// <param name="filePath">The file to which to save the appointments.</param>
        public void ExportCalendar(string filePath)
        {
            CalendarManager.ExportCalendar(filePath, CalendarFilePath);
        }

        /// <summary>
        /// Imports an appointment into the current calendar, or the calendar
        /// selected by the user when prompted if there is not current calendar.
        /// </summary>
        /// <param name="appt">The appointment to import.</param>
        /// <param name="filePath">The file path of the calendar to import into.</param>
        public void Import(Appointment appt, string filePath)
        {
            CalendarManager.Import(filePath, appt);
        }

        /// <summary>
        /// Exports an appointment to another calendar.
        /// </summary>
        /// <param name="appt">The appointment to export.</param>
        /// <param name="filePath">The path of the calendar file to export to.</param>
        public void Export(Appointment appt, string filePath)
        {
            CalendarManager.Export(filePath, appt);
        }

        /// <summary>
        /// Gets all windows contacts associated with the user currently logged in.
        /// </summary>
        /// <returns>A list of Attendees converted from a C4F.DevKit.Contacts.SimpleContactView object.</returns>
        /// <remarks>Use the Contacts assembly shipped with the VS Express Developer Kit. </remarks>
        public List<Attendee> GetAllWindowsContactsAsAttendees()
        {            
            return _calendarManager.GetAllWindowsContactsAsAttendees();            
        }

        #endregion Public Methods
    }
}
